import { Inject, Provide } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { In, Repository } from 'typeorm';
import { CreateGroupDto, UpdateGroupDto, QueryGroupDto, QueryGroupStudentDto } from '@dto/group.dto';
import { GroupEntity } from '@entity/group.entity';
import { resBuild } from '../utils/resBuild';
import { getOperator, isEmpty } from '../utils';
import { TeacherEntity } from '@entity/teacher.entity';
import { MajorEntity } from '@entity/major.entity';
import { StudentEntity } from '@entity/user/student.entity';
import { SysDept } from '@entity/framework/system/SysDept';

@Provide()
export class GroupDao {
  @Inject()
  ctx: Context;
  @InjectEntityModel(GroupEntity)
  groupEntityRep: Repository<GroupEntity>;

  @InjectEntityModel(TeacherEntity)
  teacherEntityRep: Repository<TeacherEntity>;

  @InjectEntityModel(MajorEntity)
  majorEntityRep: Repository<MajorEntity>;

  @InjectEntityModel(SysDept)
  deptEntityRep: Repository<SysDept>;

  @InjectEntityModel(StudentEntity)
  studentEntityRep: Repository<StudentEntity>;

  async create(createGroupDto: CreateGroupDto) {
    await this.groupEntityRep.manager.transaction(async manager => {
      const groupRepo = manager.getRepository(GroupEntity);
      const majorRepo = manager.getRepository(MajorEntity);

      // 创建分组
      const entity = groupRepo.create(createGroupDto);
      entity.setCreateBy(getOperator(this.ctx));
      entity.setUpdateBy(getOperator(this.ctx));
      const savedGroup = await groupRepo.save(entity);

      // 更新关联专业的 group_flag 和 groupId
      if (createGroupDto.majorIds) {
        const majorIds = createGroupDto.majorIds
          .split(',')
          .filter(id => id && id.trim())
          .map(id => parseInt(id.trim()));

        if (majorIds.length > 0) {
          await majorRepo.update(
            { majorId: In(majorIds) },
            {
              groupFlag: '1',
              groupId: savedGroup.groupId,
              updateBy: getOperator(this.ctx),
              updateTime: new Date(),
            }
          );
        }
      }
    });

    return resBuild.success();
  }

  /**
   * 根据年级ID获取分组列表（不分页）
   */
  async listByGrade(gradeId: number) {
    const groups = await this.groupEntityRep
      .createQueryBuilder('entity')
      .leftJoinAndSelect('entity.grade', 'grade')
      .leftJoinAndSelect('entity.dept', 'dept')
      .where('entity.gradeId = :gradeId', { gradeId })
      .andWhere('entity.delFlag = :delFlag', { delFlag: '0' })
      .orderBy('entity.createTime', 'DESC')
      .getMany();

    // 加载每个分组的专业和教师信息
    const result = await Promise.all(
      groups.map(async item => {
        const majorIds = item.majorIds
          ? item.majorIds.split(',').filter(id => id && id.trim())
          : [];
        const majors =
          majorIds.length > 0
            ? await this.majorEntityRep.find({
              where: {
                majorId: In(majorIds),
              },
            })
            : [];

        const teacherIds = item.teacherIds
          ? item.teacherIds.split(',').filter(id => id && id.trim())
          : [];
        const teachers =
          teacherIds.length > 0
            ? await this.teacherEntityRep.find({
              where: {
                teacherId: In(teacherIds),
              },
              relations: ['user'],
            })
            : [];

        item.majors = majors;
        item.teachers = teachers;
        return item;
      })
    );

    return resBuild.data(result);
  }
  async listByGradeAndTeacher(gradeId: number, teacherId: number) {
    const groups = await this.groupEntityRep
      .createQueryBuilder('entity')
      .leftJoinAndSelect('entity.grade', 'grade')
      .leftJoinAndSelect('entity.dept', 'dept')
      .where('entity.gradeId = :gradeId', { gradeId })
      .andWhere('entity.teacherIds LIKE :teacherIds', {
        teacherIds: `%${teacherId}%`,
      })
      .andWhere('entity.delFlag = :delFlag', { delFlag: '0' })
      .andWhere('entity.endTime > :currentTime', { currentTime: new Date() })
      .orderBy('entity.createTime', 'DESC')
      .getMany();
    return resBuild.data(groups);
  }

  async list(query: QueryGroupDto) {
    const entity = this.groupEntityRep
      .createQueryBuilder('entity')
      .leftJoinAndSelect('entity.grade', 'grade')
      .leftJoinAndSelect('entity.dept', 'dept')
      .where('entity.delFlag = :delFlag', { delFlag: '0' });

    if (!isEmpty(query.majorIds)) {
      entity.andWhere('entity.majorIds = :majorIds', {
        majorIds: query.majorIds,
      });
    }
    if (!isEmpty(query.teacherIds)) {
      entity.andWhere('entity.teacherIds = :teacherIds', {
        teacherIds: query.teacherIds,
      });
    }
    if (!isEmpty(query.groupName)) {
      entity.andWhere('entity.groupName LIKE :groupName', {
        groupName: `%${query.groupName}%`,
      });
    }
    if (!isEmpty(query.teamMax)) {
      entity.andWhere('entity.teamMax = :teamMax', { teamMax: query.teamMax });
    }
    if (!isEmpty(query.teacherMax)) {
      entity.andWhere('entity.teacherMax = :teacherMax', {
        teacherMax: query.teacherMax,
      });
    }
    if (!isEmpty(query.startTime)) {
      entity.andWhere('entity.startTime >= :startTime', {
        startTime: query.startTime,
      });
    }
    if (!isEmpty(query.endTime)) {
      entity.andWhere('entity.endTime <= :endTime', { endTime: query.endTime });
    }
    if (!isEmpty(query.status)) {
      entity.andWhere('entity.status = :status', { status: query.status });
    }
    if (!isEmpty(query.deptId)) {
      entity.andWhere('entity.deptId = :deptId', { deptId: query.deptId });
    }
    if (query.pageNum && query.pageSize) {
      entity.skip(query.pageSize * (query.pageNum - 1)).take(query.pageSize);
    }
    entity.addOrderBy('entity.createTime', 'DESC');
    let [list, total] = await entity.getManyAndCount();
    const result = await Promise.all(list.map(async (item) => {
      const majorIds = item.majorIds ? item.majorIds.split(',').filter(id => id && id.trim()) : [];
      const majors = majorIds.length > 0 ? await this.majorEntityRep.find({
        where: {
          majorId: In(majorIds)
        }
      }) : [];

      const teacherIds = item.teacherIds ? item.teacherIds.split(',').filter(id => id && id.trim()) : [];
      const teachers = teacherIds.length > 0 ? await this.teacherEntityRep.find({
        where: {
          teacherId: In(teacherIds)
        }, relations: ['user']
      }) : [];
      item.majors = majors
      item.teachers = teachers
      return item
    }));
    return resBuild.list(result, total);
  }

  async detail(groupId: number) {
    const detailInfo = await this.groupEntityRep.findOneBy({ groupId });
    const majorIds = detailInfo.majorIds ? detailInfo.majorIds.split(',').filter(id => id && id.trim()) : [];
    const majors = majorIds.length > 0 ? await this.majorEntityRep.find({
      where: {
        majorId: In(majorIds)
      }
    }) : [];
    detailInfo.majors = majors
    return resBuild.data(detailInfo);
  }

  async update(updateGroupDto: UpdateGroupDto) {
    await this.groupEntityRep.manager.transaction(async manager => {
      const groupRepo = manager.getRepository(GroupEntity);
      const majorRepo = manager.getRepository(MajorEntity);

      const { groupId } = updateGroupDto;

      // 获取旧的分组信息
      const oldGroup = await groupRepo.findOne({ where: { groupId } });
      if (!oldGroup) {
        throw new Error('分组不存在');
      }

      // 解析旧的和新的专业ID列表
      const oldMajorIds = oldGroup.majorIds
        ? oldGroup.majorIds.split(',').filter(id => id && id.trim()).map(id => parseInt(id.trim()))
        : [];

      const newMajorIds = updateGroupDto.majorIds
        ? updateGroupDto.majorIds.split(',').filter(id => id && id.trim()).map(id => parseInt(id.trim()))
        : [];

      // 找出被移除的专业（在旧列表中但不在新列表中）
      const removedMajorIds = oldMajorIds.filter(id => !newMajorIds.includes(id));

      // 找出新增的专业（在新列表中但不在旧列表中）
      const addedMajorIds = newMajorIds.filter(id => !oldMajorIds.includes(id));

      // 更新分组信息
      const entity = groupRepo.create(updateGroupDto);
      entity.setUpdateBy(getOperator(this.ctx));
      await groupRepo.save(entity);

      // 将移除的专业的 group_flag 改为 '0'，清空 groupId
      if (removedMajorIds.length > 0) {
        await majorRepo.update(
          { majorId: In(removedMajorIds) },
          {
            groupFlag: '0',
            groupId: null,
            updateBy: getOperator(this.ctx),
            updateTime: new Date(),
          }
        );
      }

      // 将新增的专业的 group_flag 改为 '1'，设置 groupId
      if (addedMajorIds.length > 0) {
        await majorRepo.update(
          { majorId: In(addedMajorIds) },
          {
            groupFlag: '1',
            groupId: groupId,
            updateBy: getOperator(this.ctx),
            updateTime: new Date(),
          }
        );
      }
    });

    return resBuild.success();
  }

  async remove(groupIds: Array<number>) {
    await this.groupEntityRep.manager.transaction(async manager => {
      const groupRepo = manager.getRepository(GroupEntity);
      const majorRepo = manager.getRepository(MajorEntity);

      // 获取要删除的分组信息
      const groups = await groupRepo.find({
        where: { groupId: In(groupIds) },
      });

      // 收集所有关联的专业ID
      const allMajorIds: number[] = [];
      for (const group of groups) {
        if (group.majorIds) {
          const majorIds = group.majorIds
            .split(',')
            .filter(id => id && id.trim())
            .map(id => parseInt(id.trim()));
          allMajorIds.push(...majorIds);
        }
      }

      // 标记分组为删除
      await groupRepo.update(
        { groupId: In(groupIds) },
        {
          delFlag: '1',
          updateBy: getOperator(this.ctx),
          updateTime: new Date(),
        }
      );

      // 将关联专业的 group_flag 改为 '0'，清空 groupId
      if (allMajorIds.length > 0) {
        await majorRepo.update(
          { majorId: In(allMajorIds) },
          {
            groupFlag: '0',
            groupId: null,
            updateBy: getOperator(this.ctx),
            updateTime: new Date(),
          }
        );
      }
    });

    return resBuild.success();
  }
  async detailStudent(groupId: number, query: QueryGroupStudentDto) {
    const groupInfo = await this.groupEntityRep.findOneBy({ groupId });
    const majorIds = groupInfo.majorIds.split(',');

    const entity = this.studentEntityRep.createQueryBuilder('entity')
      .leftJoinAndSelect('entity.user', 'user')
      .leftJoinAndSelect('entity.major', 'major')
      .leftJoinAndSelect('entity.grade', 'grade')
      .leftJoinAndSelect('user.dept', 'dept')
      .leftJoinAndSelect('entity.studentTeam', 'studentTeam')
      .leftJoinAndSelect('studentTeam.team', 'team')
      .where(`entity.majorId IN (${majorIds.join(',')})`);
    if (query.isTeam === true) {
      entity.andWhere('studentTeam.studentId IS NOT NULL');
    }
    if (query.isTeam === false) {
      entity.andWhere('studentTeam.studentId IS NULL');
    }
    if (!isEmpty(query.stuId)) {
      entity.andWhere('entity.stuId LIKE :stuId', { stuId: `%${query.stuId}%` });
    }
    if (!isEmpty(query.nickName)) {
      entity.andWhere('user.nickName LIKE :nickName', { nickName: `%${query.nickName}%` });
    }
    if (query.pageNum && query.pageSize) {
      entity.skip(query.pageSize * (query.pageNum - 1)).take(query.pageSize);
    }
    entity.addOrderBy('entity.createTime', 'DESC');
    const [list, total] = await entity.getManyAndCount();
    return resBuild.list(list, total);
  }

  /**
   * 获取分组成员信息（学生+教师，分页）
   */
  async detailTeacher(groupId: number) {
    // 获取分组信息
    const groupInfo = await this.groupEntityRep.findOne({
      where: { groupId },
      relations: ['grade', 'dept'],
    });

    if (!groupInfo) {
      throw new Error('分组不存在');
    }
    const teacherIds = groupInfo.teacherIds
      ? groupInfo.teacherIds.split(',').filter(id => id && id.trim()).map(id => parseInt(id.trim()))
      : [];

    // 获取教师信息（不分页，因为教师数量通常较少）
    const teachers = teacherIds.length > 0
      ? await this.teacherEntityRep.find({
        where: {
          teacherId: In(teacherIds),
          delFlag: '0',
          status: '0',
        },
        relations: ['user', 'user.dept'],
      })
      : [];
    return resBuild.data({
      list: teachers,
      total: teachers.length,
    });
  }
}
